package org.skyui.core;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
import org.json.JSONObject;
import org.skyui.accesscontrol.HumanAuthenticator;
import org.skyui.beanmanagers.BeanSetManager;
import org.skyui.beans.OrganizationBean;
import org.skyui.controllers.NavigationController;
import org.skyui.jpa.JPAManager;

import com.baycrypt.server.beans.people.UserBean;
import com.baycrypt.server.fbmanager.FBManager;
import com.baycrypt.server.utils.BayCryptUtils;
import com.baycrypt.vaadinui.ProductEditions;
import com.vaadin.Application;
import com.vaadin.service.ApplicationContext;
import com.vaadin.terminal.ExternalResource;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.terminal.gwt.server.HttpServletRequestListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.Label;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.SplitPanel;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

public abstract class UIApplication extends Application implements
	ApplicationContext.TransactionListener, HttpServletRequestListener {

    protected static ThreadLocal<UIApplication> currentApplication = new ThreadLocal<UIApplication>();

    public static UIApplication getInstance() {
	return currentApplication.get();
    }

    private NavigationController navigationController;

    protected String userName;
    protected OrganizationBean organization;
    protected String role = "";
    protected boolean fbAuthenticated = false;
    protected VerticalLayout vl;
    private String appWindowName;
    private String brandImageFileName;
    private String coovaRedirect;

    public UIApplication() {
	super();
    }

    private String productEdition;

    public String getProductEdition() {
	return productEdition;
    }

    public void setProductEdition(String productEdition) {
	System.out.println("Edition" + productEdition);
	this.productEdition = productEdition;
    }

    public String getCoovaRedirect() {
	return coovaRedirect;
    }

    public void setCoovaRedirect(String coovaRedirect) {
	this.coovaRedirect = coovaRedirect;
    }

    public OrganizationBean getOrganization() {
	if (organization == null)
	    throw new IllegalStateException("Null organization");
	return this.organization;
    }

    public String getRole() {
	return this.role;
    }

    public String getUserName() {
	return this.userName;
    }

    protected void setOrganization(OrganizationBean organization) {
	if (organization == null)
	    throw new IllegalStateException("Null organization");
	this.organization = organization;

    }

    public void transactionStart(Application application, Object o) {
	if (application == this) {
	    currentApplication.set(this);
	}
    }

    public void transactionEnd(Application application, Object o) {
	if (application == this) {
	    currentApplication.set(null);
	    currentApplication.remove();
	}
    }

    private String persistentUnit;

    public void init() {

	try {
	    JPAManager.init(getPersistentUnit());
	} catch (Exception e) {
	    BayCryptUtils.logger().error(e);
	}
	getContext().addTransactionListener(this);
	// Need to set a theme for ThemeResources to work
	setTheme("reindeer");
    }

    public void authenticate(String login, String password,
	    String productEdition) throws Exception {

	UserBean userBean;

	if ((userBean = HumanAuthenticator.authenticateUser(login, password,
		productEdition)) == null) {
	    throw new IllegalArgumentException("Login failed !");
	} else {
	    this.userName = login;
	    if (userBean.isAdmin()) {
		role = "ADMIN";
		if ("root@baycrypt.com".equals(userBean.getEmail())) {
		    role = "ROOT";
		}
	    } else {
		role = "USER";
	    }

	    setOrganization(userBean.getOrganization());
	    setProductEdition(productEdition);
	}

	loadProtectedResources(false);
    }

    public void setPersistentUnit(String persistentUnit) {
	this.persistentUnit = persistentUnit;
    }

    public String getPersistentUnit() {
	return persistentUnit;
    }

    public void setAppWindowName(String appWindowName) {
	this.appWindowName = appWindowName;
    }

    public String getAppWindowName() {
	return appWindowName;
    }

    public void setBrandImageFileName(String brandImageFileName) {
	this.brandImageFileName = brandImageFileName;
    }

    public String getBrandImageFileName() {
	return brandImageFileName;
    }

    public void loadProtectedResources(boolean isCaptive) {
	// Create new window for the application and give the window a visible.

	final Window main = new Window(getAppWindowName());
	main.setScrollable(true);
	setMainWindow(main);

	final SplitPanel split = new SplitPanel(
		SplitPanel.ORIENTATION_HORIZONTAL);
	split.setSplitPosition(150, Sizeable.UNITS_PIXELS);
	main.setContent(split);
	VerticalLayout vl1 = new VerticalLayout();
	Label brandLabel = new Label();
	brandLabel.setIcon(new ThemeResource(getBrandImageFileName()));
	vl1.addComponent(brandLabel);

	Table tl = this.getNavigationController().initializeMenuTable(this);
	vl1.addComponent(tl);
	vl1.setComponentAlignment(tl, Alignment.TOP_CENTER);

	split.addComponent(vl1);
	split.setLocked(true);

	this.vl = new VerticalLayout();
	this.vl.setMargin(true);
	this.vl.addComponent(this.getNavigationController()
		.getNavigationTabSheet());
	split.addComponent(this.vl);
	if (isCaptive)
	    displayCoovaWindow();
    }

    void displayCoovaWindow() {
	final Window chilliWindow = new Window("SkyBirdz Login");

	Label brand = new Label();
	brand.setIcon(new ThemeResource(getBrandImageFileName()));
	chilliWindow.addComponent(brand);

	Embedded browser = new Embedded("", new ExternalResource(
		ChilliParametrsHolder.generateChilliFreeLoginUrl()));
	browser.setHeight("1px");
	browser.setWidth("1px");
	browser.setType(Embedded.TYPE_BROWSER);
	chilliWindow.addComponent(browser);
	chilliWindow.addComponent(new Label("Login Successful"));
	chilliWindow.addComponent(new Label(""));
	Button closeButton = new Button("Proceed to SkyBirdz");
	closeButton.addListener(new ClickListener() {

	    @Override
	    public void buttonClick(ClickEvent event) {
		getMainWindow().removeWindow(chilliWindow);
	    }
	});
	chilliWindow.addComponent(closeButton);
	chilliWindow.setSizeFull();
	chilliWindow.setImmediate(true);
	getMainWindow().addWindow(chilliWindow);
    }

    public void setNavigationController(
	    NavigationController navigationController) {
	this.navigationController = navigationController;
    }

    public NavigationController getNavigationController() {
	return navigationController;
    }

    private static String clientId = "189165447788348";
    private static String redirectURI = "http://wiki.infotechbiz.biz:8443/skycommand/";
    private static String clientSecret = "4f4121f6c780712b2f398ab541ffe149";

    protected OrganizationBean connectFB(String query, boolean isCaptive)
	    throws Error, IOException {
	URL url;
	String redirectURI = getRedirectURI();
	if (isCaptive) {
	    redirectURI = redirectURI + "captive/";
	}
	url = new URL(
		"https://graph.facebook.com/oauth/access_token?client_id="
			+ getClientId() + "&" + "redirect_uri=" + redirectURI
			+ "&" + "client_secret=" + getClientSecret() + "&"
			+ "code=" + query);

	System.out.println("Redirect " + redirectURI);
	BufferedReader in;
	in = new BufferedReader(new InputStreamReader(url.openStream()));
	String inputLine;

	inputLine = in.readLine();
	if (inputLine == null) {
	    throw new IOException("Null line");
	}
	in.close();
	if (!inputLine.startsWith("access_token=")) {
	    System.err.println("Invalid prefix" + inputLine);
	    throw new IOException("Invalid prefix" + inputLine);
	}
	String accessToken = inputLine.substring("access_token=".length());
	return (new FBManager()).createUsersFromFB(accessToken);
	
    }

    @Override
    public void onRequestEnd(HttpServletRequest request,
	    HttpServletResponse response) {
	// TODO Auto-generated method stub

    }

    // add variables

    public void onRequestStart(HttpServletRequest request,
	    HttpServletResponse response) {

	String url = request.getRequestURI();
	boolean isCaptive = false;
	System.out.println(url);
	isCaptive = url.indexOf("captive") >= 0;
	currentApplication.set(this);
	System.out.println("Is Captive " + isCaptive);
	String query = request.getQueryString();

	if (isCaptive) {
	    // add your code
	    if (request.getParameter("challenge") != null)
		ChilliParametrsHolder.setChallenge(request
			.getParameter("challenge"));
	    if (request.getParameter("uamip") != null)
		ChilliParametrsHolder.setUamip(request.getParameter("uamip"));
	    if (request.getParameter("uamport") != null)
		ChilliParametrsHolder.setUamport(request
			.getParameter("uamport"));
	    if (request.getParameter("userurl") != null)
		ChilliParametrsHolder.setUserurl(request
			.getParameter("userurl"));

	}

	if (query != null && query.startsWith("code=")) {
	    query = query.substring("code=".length());
	    
	    try {
		organization = connectFB(query, isCaptive);
	    }
	    catch (IOException e) {
		e.printStackTrace();
	    }
	    
	    
	    this.userName = "fb:" + organization.getName();
	    this.role = "ADMIN";
	    this.fbAuthenticated = true;

	    loadProtectedResources(isCaptive);
	    try {
		if (isCaptive)
		    response.sendRedirect("http://wiki.infotechbiz.biz:8443/skycommand/");
	    } catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	    }
	}

    }

    public void setClientId(String clientId) {
	this.clientId = clientId;
    }

    public String getClientId() {
	return clientId;
    }

    public void setRedirectURI(String redirectURI) {
	this.redirectURI = redirectURI;
    }

    public String getRedirectURI() {
	return redirectURI;
    }

    public void setClientSecret(String clientSecret) {
	this.clientSecret = clientSecret;
    }

    public String getClientSecret() {
	return clientSecret;
    }

}